import React, { ReactNode, forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import "mapbox-gl/dist/mapbox-gl.css";
// import './../../libs/smart-map/dist/assets/style.css'
import './assets/style.css'
import SmartMapLayerManage from './kits/SmartMapLayerManage';
import SmartMapZoomUtilsBtn from './kits/SmartMapZoomUtilsBtn';
import { MapStatus, MapTopic, SmartMapMarker, SmartMapProps } from './typings';
import SmartMapProvider from './provider/SmartMapProvider';
import SmartMapLayerUtilsBtn from './kits/SmartMapLayerBtn';
import { adaptLocationPoint, isEmpty, mapZoomStepInfoList, toastShort } from './utils';
import { Spin } from 'antd';
import SmartMapLegend from './kits/SmartMapLegend';

const SmartMap = (props: SmartMapProps, ref: any) => {
    useImperativeHandle(ref, () => ({
        setMapZoom: _handleSetMapZoom,
        setMapCenter: _handleSetMapCenter,
        setMapMarkerList: _handleSetMapMarkerList,
        getMapBoxInstance: _handleGetMapBoxInstance,
    }));

    const {
        onMapLoaded = () => { },
        onPressMarker = () => { },
        initMapCenter,
        initMapZoom,
        tdt_map_token,
        mapbox_token,
        mapMountingRootId,
        uploadActionUrl,
        defaultMapLayerPid = null,
        addMapLayerPromiseFunc,
        editMapLayerPromiseFunc,
        deleteMapLayerPromiseFunc,
        queryMapLayerPromiseFunc,
    } = props;

    let satelliteSources = {
        "tdt-satellite-osm-tiles-image": {
            type: "raster",
            tiles: [
                "https://t2.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=" +
                tdt_map_token,
            ],
            tileSize: 256,
        },
        "tdt-satellite-osm-osm-tiles-marker": {
            type: "raster",
            tiles: [
                "https://t2.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=" +
                tdt_map_token,
            ],
            tileSize: 256,
        },
    };
    let satelliteLayers = [
        {
            id: "tdt-satellite-osm-tiles-image-layer",
            type: "raster",
            source: "tdt-satellite-osm-tiles-image",
        },
        {
            id: "tdt-satellite-osm-tiles-marker-layer",
            type: "raster",
            source: "tdt-satellite-osm-osm-tiles-marker",
        },
    ];
    const mapSpriteLink =
        "https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v11/sprite?access_token=" +
        mapbox_token;
    const mapGlyphsLink =
        "mapbox://fonts/mapbox/{fontstack}/{range}.pbf?sku=101BaIdi5dNyK&access_token=" +
        mapbox_token;

    const [mapStyleConfig, setMapStyleConfig] = useState({
        version: 8,
        sprite: mapSpriteLink,
        glyphs: mapGlyphsLink,
        sources: satelliteSources,
        layers: satelliteLayers,
    })

    const [mapStatus, setMapStatus] = useState<MapStatus>({
        zoom: 10.5,
        center: [100.169970, 25.778000],
        pitch: 0,
        bearing: 0,
    });

    const [mapLoading, setMapLoading] = useState(false);

    const [viewPointHeight, setViewPointHeight] = useState(0);

    const mapInstance = useRef(null);

    const thirdPartyLayers = useRef<MapTopic[]>([]);

    const [checkedThirdPartyLayerList, setCheckedThirdPartyLayerList] = useState<MapTopic[]>([]);

    useEffect(() => {
        setMapLoading(true);
        mapboxgl.accessToken = mapbox_token;
        const _initMapCenter = initMapCenter ? initMapCenter : [100.169970, 25.778000];
        const _initMapZoom = initMapZoom ? initMapZoom : 11;
        var map = new mapboxgl.Map({
            container: mapMountingRootId,
            //@ts-ignore
            style: mapStyleConfig,
            //@ts-ignore
            center: _initMapCenter,
            zoom: _initMapZoom,
            pitch: 0,
            bearing: 0,
            antialias: true,
            maxZoom: 17,
        });
        mapInstance.current = map;
        const initMapStatus: MapStatus = {
            center: _initMapCenter,
            zoom: _initMapZoom,
            pitch: 0,
            bearing: 0,
        }
        setMapStatus(initMapStatus);
        map.on("load", function () {
            setMapLoading(false)
            map.addControl(
                new mapboxgl.ScaleControl({
                    maxWidth: 80,
                    unit: "metric",
                }),
                "bottom-right"
            );
            onMapLoaded && onMapLoaded();
        });
        map.on("zoomend", (e) => {
            const mapCurrentZoom = map.getZoom();
            let _mapStatus = mapStatus;
            _mapStatus.zoom = mapCurrentZoom;
            setMapStatus({ ..._mapStatus });

        });
        map.on("moveend", (e) => {
            const mapCurrentCenter = map.getCenter();
            const _mapCurrentCenter = [mapCurrentCenter.lng, mapCurrentCenter.lat];
            let _mapStatus = mapStatus;
            _mapStatus.center = _mapCurrentCenter;
            setMapStatus({ ..._mapStatus });
        });
        map.on("pitchend", (e) => {
            const mapCurrentPitch = map.getPitch();
            let _mapStatus = mapStatus;
            _mapStatus.pitch = mapCurrentPitch;
            setMapStatus({ ..._mapStatus });
        });
    }, []);

    const [layerManageDrawerOpen, setLayerManageDrawerOpen] = useState(false);

    const handleSetLayerManageDrawerOpen = (e: boolean) => {
        setLayerManageDrawerOpen(e)
    }

    const handleSetCheckedThirdPartyLayerList = (e: MapTopic[]) => {
        setCheckedThirdPartyLayerList([...e]);
    }

    const _handleSetMapZoom = (newZoom: number) => {
        handleSetMapZoom(newZoom)
    }

    const _handleSetMapCenter = (newCenter: number[]) => {
        const tempMapInstance = mapInstance.current;
        let _mapStatus = mapStatus;
        _mapStatus.center = newCenter;
        setMapStatus({ ..._mapStatus })
        tempMapInstance.easeTo(_mapStatus);
    }

    const convertReactNodeToElement = (reactNode: ReactNode) => {
        const container = document.createElement('div');
        //@ts-ignore
        React.render(reactNode, container);
        return container.firstChild;

    }

    // const testAddMarker = () => {
    //     const tempMapInstance = mapInstance.current;
    //     const MarkerEl = () => {
    //         return (
    //             // ReactDOMServer.renderToString(
    //             <div style={{ backgroundColor: 'red' }}>
    //                 <p>1111</p>
    //             </div>
    //             // )
    //         )
    //     }
    //     // console.log(ReactDOMServer.renderToString(<button>333</button>));
    //     // console.log("markerEl--->", markerEl())
    //     //@ts-ignore
    //     let marker2 = new mapboxgl.Marker({ element: React.createElement(<MarkerEl />) })
    //         // let marker2 = new mapboxgl.Marker({element: <div style={{width: '100px', height: '200px', backgroundColor: 'red'}}>sss</div>})
    //         .setLngLat([100.169970, 25.778000])
    //         .setOffset([0, -1])
    //         .addTo(tempMapInstance); // 将标记添加到地图上
    // };

    const _handleGetMapBoxInstance = () => {
        const tempMapInstance = mapInstance.current;
        return tempMapInstance;
    }

    const _handleSetMapMarkerList = (markerList: SmartMapMarker[]) => {

    }

    const caculateViewPointHeight = () => {
        const {
            zoom,
        } = mapStatus;
        const mapCurrentZoom = zoom;
        const currentMapZoomLeverFloor = Math.floor(mapCurrentZoom);
        const currentMapZoomLeverCeil = Math.ceil(mapCurrentZoom);
        const findFloorZoom = mapZoomStepInfoList.find((zoomInfo) => {
            return zoomInfo.zoom == currentMapZoomLeverFloor;
        });
        const findCeilZoom = mapZoomStepInfoList.find((zoomInfo) => {
            return zoomInfo.zoom == currentMapZoomLeverCeil;
        });
        const viewPointHeightFloor = Number(findFloorZoom["viewPointHeight"]);
        const viewPointHeightCeil = Number(findCeilZoom["viewPointHeight"]);
        const heightDiff =
            (viewPointHeightFloor - viewPointHeightCeil) *
            (mapCurrentZoom - currentMapZoomLeverFloor);
        const _viewPointHeight = viewPointHeightFloor + heightDiff;
        setViewPointHeight(_viewPointHeight)
    };

    useEffect(() => {
        caculateViewPointHeight();
    }, [mapStatus]);

    useEffect(() => {
        const neddToAddThirdPartyLayerList: MapTopic[] = [];
        const needToRemoveThirdPartyLayerList: MapTopic[] = [];
        const currentThirdPartyLayerList: MapTopic[] = thirdPartyLayers.current;
        checkedThirdPartyLayerList.forEach(newMapLayer => {
            const findExist = currentThirdPartyLayerList.find(oldMapLayer => {
                return oldMapLayer.id == newMapLayer.id;
            })
            if (!findExist) {
                neddToAddThirdPartyLayerList.push(newMapLayer)
            }
        })
        currentThirdPartyLayerList.forEach(oldMapLayer => {
            const findExist = checkedThirdPartyLayerList.find(newMapLayer => {
                return newMapLayer.id == oldMapLayer.id;
            })
            if (!findExist) {
                needToRemoveThirdPartyLayerList.push(oldMapLayer)
            }
        })
        console.log("neddToAddThirdPartyLayerList--->", neddToAddThirdPartyLayerList);
        neddToAddThirdPartyLayerList.forEach(layer => {
            addThirdPartyLayer(layer);
        })
        console.log("needToRemoveThirdPartyLayerList--->", needToRemoveThirdPartyLayerList);
        needToRemoveThirdPartyLayerList.forEach(layer => {
            removeThirdPartyLayer(layer)
        })
        thirdPartyLayers.current = checkedThirdPartyLayerList;
    }, [checkedThirdPartyLayerList]);

    const adaptMapCurrentCenter = () => {
        if (isEmpty(mapStatus.center) || mapStatus.center.length == 0) {
            return "地图初始化中...";
        }
        const {
            center
        } = mapStatus;
        return adaptLocationPoint(center[0], center[1]);
    };

    const adaptMapCurrentPitch = () => {
        const {
            pitch
        } = mapStatus;
        if (!isEmpty(pitch)) {
            return pitch.toFixed(2) + "°";
        }
    };

    const adaptViewPointHeight = () => {
        return viewPointHeight.toFixed(1) + "公里";
    };

    const getLayerId = (layer: MapTopic) => {
        try {
            return `layer-id-${layer.id}`; //common-map-
        } catch (e) {
            return "";
        }
    };

    const getLayerType = (layer: MapTopic) => {
        let result = "";
        switch (layer.layerType) {
            case "shape":
                result = "fill";
                break;
            case "line":
                result = "line";
                break;
            case 'symbol':
                result = "circle";
                break;
            default:
                result = "fill";
        }
        return result;
    };

    const getSourceId = (layer) => {
        try {
            return `source-id-${layer.id}`;
        } catch (e) {
            return "";
        }
    };

    const getLayerStyle = (layer: MapTopic) => {
        const currentLayerType = getLayerType(layer);
        const layerDefaultColor = JSON.parse(layer.styleConfig)['themeColor'];
        const defaultFillStyle = {
            "fill-color": "rgba(103, 194, 58, 0.6)",
            "fill-opacity": 0.9,
            "fill-outline-color": "rgba(103, 194, 58, 1)",
        };
        const defaultLineStyle = {
            "line-width": 1,
            "line-color": "rgba(103, 194, 58, 0.6)",
        };
        const defaultCircleStyle = {
            "circle-radius": [
                "interpolate",
                ["linear"],
                ["zoom"],
                1,
                2,
                10,
                4,
                22,
                10,
            ],
            "circle-stroke-width": [
                "interpolate",
                ["linear"],
                ["zoom"],
                1,
                0.2,
                10,
                0.5,
                22,
                3,
            ],
            "circle-stroke-color": [
                "interpolate",
                ["linear"],
                ["zoom"],
                0,
                "rgba(103, 194, 58, 0.6)",
                22,
                "rgba(103, 194, 58, 0.6)",
            ],
            "circle-stroke-opacity": [
                "interpolate",
                ["linear"],
                ["zoom"],
                0,
                0.72,
                22,
                0.9,
            ],
            "circle-color": "rgba(103, 194, 58, 0.6)",
        };
        let layerStyle: any = null;
        switch (currentLayerType) {
            case 'fill':
                layerStyle = defaultFillStyle;
                layerStyle['fill-color'] = layerDefaultColor;
                layerStyle['fill-outline-color'] = layerDefaultColor;
                break;
            case 'line':
                layerStyle = defaultLineStyle;
                layerStyle['line-color'] = layerDefaultColor;
                break;
            case 'circle':
                layerStyle = defaultCircleStyle;
                layerStyle['circle-stroke-color'][4] = layerDefaultColor;
                layerStyle['circle-stroke-color'][6] = layerDefaultColor;
                layerStyle['circle-stroke-color'] = layerDefaultColor;
                break;
            default:
                break;
        }
        console.log("layerStyle--->", layerStyle)
        return layerStyle;
    }

    const renderLayer = (layer: MapTopic) => {
        const layerId = getLayerId(layer);
        const sourceId = getSourceId(layer);
        const tempMapInstance = mapInstance.current;
        const sourceIsExist = tempMapInstance.getSource(sourceId);
        if (!sourceIsExist) {
            tempMapInstance.addSource(sourceId, {
                type: "geojson",
                data: layer.geoJSON,
            });
        }
        tempMapInstance.addLayer({
            id: layerId,
            source: sourceId,
            name: layerId,
            layout: {
                visibility: "visible",
            },
            type: getLayerType(layer),
            paint: getLayerStyle(layer),
        });
    };

    const addThirdPartyLayer = (newThirdPartyLayer: MapTopic) => {
        const tempMapInstance = mapInstance.current;
        const tempThirdPartyLayers = thirdPartyLayers.current;
        tempThirdPartyLayers.push(newThirdPartyLayer);
        thirdPartyLayers.current = tempThirdPartyLayers;
        if (!tempMapInstance) {
            return toastShort('error', "地图基础服务尚未加载完毕，请稍后添加图层");
        }
        const currentLayerId = getLayerId(newThirdPartyLayer);
        const layerExist = tempMapInstance.getLayer(currentLayerId);
        if (layerExist == undefined || layerExist == false) {
            renderLayer(newThirdPartyLayer);
        }
    };

    const removeThirdPartyLayer = (thirdPartyLayer: MapTopic) => {
        const tempMapInstance = mapInstance.current;
        const tempThirdPartyLayers = thirdPartyLayers.current;
        const currentLayerId = getLayerId(thirdPartyLayer);
        const currentLayerType = getLayerType(thirdPartyLayer);
        const layerExist = tempMapInstance.getLayer(currentLayerId);
        let findExistIndex = -1;
        tempThirdPartyLayers.forEach((layer, layerIndex) => {
            if (layer.id == thirdPartyLayer.id) {
                findExistIndex = layerIndex;
            }
        });
        if (findExistIndex > -1) {
            tempThirdPartyLayers.splice(findExistIndex, 1);
        }
        thirdPartyLayers.current = tempThirdPartyLayers;
        if (layerExist) {
            tempMapInstance.removeLayer(currentLayerId);
            if (currentLayerType == "fill") {
                const currentLayerOutlineLayerId = currentLayerId + "-outline";
                const currentLayerOutlineLayerExist = tempMapInstance.getLayer(
                    currentLayerOutlineLayerId
                );
                if (currentLayerOutlineLayerExist) {
                    tempMapInstance.removeLayer(currentLayerOutlineLayerId);
                }
            }
        }
    };

    const handleSetMapZoom = (newZoom) => {
        if (newZoom > 17) {
            return toastShort('warning', '已达到最大缩放级别')
        }
        if (newZoom < 1) {
            return toastShort('warning', '已达到最小缩放级别')
        }
        const tempMapInstance = mapInstance.current;
        let _mapStatus = mapStatus;
        _mapStatus.zoom = newZoom;
        setMapStatus({ ..._mapStatus })
        tempMapInstance.easeTo({ zoom: newZoom });
    }

    const handleResetMapStatus = () => {
        const tempMapInstance = mapInstance.current;
        let _mapStatus = mapStatus;
        _mapStatus.zoom = initMapZoom;
        _mapStatus.center = initMapCenter;
        _mapStatus.bearing = 0;
        _mapStatus.pitch = 0;
        setMapStatus({ ..._mapStatus })
        tempMapInstance.easeTo(_mapStatus);
    }

    return (
        <div className='smart-map-wrapper'>
            <SmartMapProvider.Provider
                value={{
                    tdt_map_token,
                    mapbox_token,
                    mapMountingRootId,
                    uploadActionUrl,
                    defaultMapLayerPid,
                    addMapLayerPromiseFunc,
                    editMapLayerPromiseFunc,
                    deleteMapLayerPromiseFunc,
                    queryMapLayerPromiseFunc,
                    checkedThirdPartyLayerList,
                    zoom: mapStatus.zoom,
                    handleSetMapZoom: handleSetMapZoom,
                    handleResetMapStatus: handleResetMapStatus,
                    center: [],
                    layerManageDrawerOpen: layerManageDrawerOpen,
                    setLayerManageDrawerOpen: handleSetLayerManageDrawerOpen,
                    handleSetCheckedThirdPartyLayerList: handleSetCheckedThirdPartyLayerList
                }}
            >
                <SmartMapLayerUtilsBtn />
                <SmartMapZoomUtilsBtn />
                <SmartMapLayerManage />
                <SmartMapLegend />
                <div id={mapMountingRootId} className="smart-map-conatiner"></div>
            </SmartMapProvider.Provider>
            <div className="current-map-center-point-info flex-row">
                <div className="current-map-center-point-info-item">
                    中心点:&nbsp;{adaptMapCurrentCenter()}
                </div>
                <div className="current-map-center-point-info-item">
                    俯仰角:&nbsp;{adaptMapCurrentPitch()}
                </div>
                <div className="current-map-center-point-info-item">
                    视点高:&nbsp;{adaptViewPointHeight()}
                </div>
            </div>
            {
                mapLoading ?
                    <div className='flex-col map-loading-wapper'>
                        <Spin />
                    </div>
                    :
                    null
            }
        </div>
    )
}

export default forwardRef(SmartMap);